#!/usr/bin/perl

use strict;
use warnings;
#use Log::Log4perl;
use lib::SimpleLogger;

# ---------------------------------------------------------------------
# Customizations starts here

# Address of your Soundbridge
my $soundbridge = '192.168.0.26';

# All modules and their parameters show up here
my @modules = (
				{
				  name => 'tagesschau.de',
                  module => 'rss',
				  params => {rss => 'http://www.tagesschau.de/xml/rss2'},
				},
				{
				  name => 'heise.de',
                  module => 'rss',
				  params => {rss => 'http://www.heise.de/newsticker/heise-atom.xml'},
				},
				{
				  name => 'tagesschau.de',
                  module => 'display_items',
				  params => {'items' => ['one', 'two', 'three']},
				},
				{
				  name => 'Hello World',
                  module => 'helloworld',
				  params => {},
				},
				{
				  name => 'Yahoo! weather',
                  module => 'yahooweather',
				  params => {location => 'GMXX4980'},
				},
				{
				  name => 'check mails',
                  module => 'checkmail',
				  params => {server => 'pop.example.com', user => 'joedoe', pass => 'secret'},
				},
			  );

# what module to show when the soundbrigde is off?
my $defaultmodule = 0;

# loglevel. Should be $DEBUG or $INFO when testing, $WARN or $ERROR in productive environments
my $loglevel = $DEBUG;

# Customizations ends here
# ---------------------------------------------------------------------


# ---------------------------------------------------------------------
#Log::Log4perl->easy_init($loglevel);
#our $logger = get_logger();
our $logger = SimpleLogger->new($loglevel);
# ---------------------------------------------------------------------


# modules are stored in ./modules
use lib 'modules';

# Extract names etc. from modules list for easier use.
my @module_names;
foreach my $module (@modules) {
	push(@module_names, $module->{name});
}

# Class to control the Roku Soundbridge
use lib::RokuUI;
my $display = RokuUI->new(host => $soundbridge, port => 4444);

# what happens if we disconnect the SB while running?
while (!$display->open) {
	# if cannot connect to ROKU retry every 60 secs
	$logger->warn('Couldn\'t connect to Roku, still trying');
	sleep 60;
}
# recover from a possible crash
$display->cmd("sketch -c exit");
$display->cmd("irman off");
#

# Start listening to the remote control
$display->cmd('irman echo');

$logger->warn('Tools up and running...');
# ---------------------------------------------------------------------
# main loop
while (1) {
	# Timeout for connection to soundbridge is now 3 seconds
	my ($prematch, $match) = $display->{connection}->waitfor(Match => '/irman: .*/', Timeout => 3);

	if ($match) {
		# A key was pressed. We now check if it was the purple one
		$match =~ s/^irman: //;

		$logger->debug("keypress in main loop: $match");

		if ($match eq 'CK_SPECIAL_POWER_STATE_CHANGED') {
			$logger->warn('power changed');
			# wait for boot
			sleep (3);
			if (not $display->ison()) {
				$logger->info('Roku is now off, starting the default module');
				showmodule($defaultmodule);
			}
			# start listening again after menu/module
			$display->cmd('irman echo');
		}

		if ($match eq 'CK_PURPLE') {
			$logger->debug('Purple key was pressed');
			$display->cmd('irman intercept');
			# why do we need to dispatch the exit key?
			$display->cmd('irman dispatch CK_EXIT');

			$logger->debug('entering menu');
			my $selection = showmenu(@module_names);

			$logger->debug("menu done, selected $selection");
			if ($selection > -1) {
				showmodule($selection)
			}
			# start listening again after menu/module
			$display->cmd('irman echo');
		};
	};
};

# /main loop
# ---------------------------------------------------------------------


# ---------------------------------------------------------------------
sub showmenu {
	my @items = @_;

	my $currentselection = 0;
    my $rc;

	$display->clear();

	while (1) {
		$logger->info("Current Selection: $currentselection");

		## TODO: The arrows (173, 0x81, 0x83) won't show up correctly
		# the sprintf will use one digit for the marker, 14 digits for the text (which will be truncated), and the last digit for the arrows
		$display->msg(text => sprintf("%c%-14.14s%c", 173, $items[$currentselection], 0x81), x => 0, y => 0, duration => 0, keygrab => 1, encoding=>'utf8');
		if ($currentselection == $#items) {
			$rc = $display->msg(text => sprintf(" %-14.14s%c", $items[0], 0x83), x => 0, y => 1, duration => 10, keygrab => 1, encoding=>'utf8');
		} else {
			$rc = $display->msg(text => sprintf(" %-14.14s%c", $items[$currentselection + 1], 0x83), x => 0, y => 1, duration => 10, keygrab => 1, encoding=>'utf8');
		}

		$logger->info("key pressed: $rc");

		if ($rc eq "CK_SELECT") {
			# the next line causes some flickering when switching to a menu
			$display->cmd("sketch -c exit");
			return $currentselection;
		} elsif (($rc eq 'timeout') or ($rc eq 'CK_EXIT') or ($rc eq 'CK_PURPLE')) {
			$display->cmd("sketch -c exit");
			return -1;
		} elsif ($rc eq 'CK_SOUTH') {
			$currentselection++;
			if ($currentselection > $#items) {
				$currentselection = 0;
			};
		} elsif ($rc eq 'CK_NORTH') {
			$currentselection--;
			if ($currentselection < 0) {
				$currentselection = $#items;
			};
		};
	}
};
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------
sub showmodule {
	my $selection = shift;

	# Load the module.
	my $modmodule = $modules[$selection]->{module};
	my %modparams = %{$modules[$selection]->{params}};
	eval "use $modmodule";

	$logger->info("loading module $modmodule");

	# Create the object and show its contents
	my $object = $modmodule->new(%modparams);
	$object->{display} = $display;
	my $rc = $object->action;

	# catch the power switch
	if ($rc eq 'CK_POWER') {
		$display->cmd('irman dispatch CK_POWER');
	}

	# release the module
	#			delete $object;
	undef $object;

	$logger->info("back from module $modmodule");
}
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------
END {
	$display->clear();
	$display->cmd("sketch -c exit");
	$display->close();
	undef $display;
	$logger->info('Goodbye.');
}
# ---------------------------------------------------------------------
